package com.seeyon.apps.brwh.kit;

import com.seeyon.ctp.common.log.CtpLogFactory;
import com.seeyon.ctp.util.Strings;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.poi.hwpf.HWPFDocument;
import org.apache.poi.hwpf.usermodel.Range;
import org.apache.poi.ooxml.POIXMLDocument;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.util.Units;
import org.apache.poi.xwpf.usermodel.*;

import java.io.*;
import java.text.MessageFormat;
import java.util.*;
import java.util.stream.Collectors;

public class BookMarksUtil {
    private static final Log log = CtpLogFactory.getLog(BookMarksUtil.class);
    private static Map<String, String> data0;
    private static Map<String, List<Map<String, String>>> subTableDatas0;

//    public static void test() throws IOException {
//        File srcFile = new File("d:/template.docx");
//        FileUtils.copyFile(new File("d:/temp.docx"), srcFile);
//        File toFile = new File("d:/toFile.docx");
//        addBookMarks(srcFile, toFile, data0, subTableDatas0);
//        srcFile.deleteOnExit();
//    }

//    public static void main(String[] args) throws Exception {
//        File srcFile = new File("d:/1.docx");
//        File toFile = new File("d:/11.docx");
//        FileUtils.copyFile(new File("d:/2.docx"), srcFile);
//
//        Map<String, String> data = new HashMap<String, String>();
//        data.put("myx2", "【myx2dsdsadadsadasd】");
//        data.put("CONTACT", "【CONTACTasdasdasdasdasdasda】");
//
//        Map<String, List<Map<String, String>>> subTableDatas = new LinkedHashMap<String, List<Map<String, String>>>();
//        String subTableName = "table";
//        String[] names = { "姓名", "年龄", "性别", "其他" };//
//        for (int i = 0; i < 2; i++) {// 表的数量
//            List<Map<String, String>> list1 = new ArrayList<Map<String, String>>();
//            String tableName = subTableName + i;
//            subTableDatas.put(tableName, list1);
//            for (int j = 0; j < 3; j++) {// 行的数量
//                Map<String, String> value = new LinkedHashMap<String, String>();
//                for (int j2 = 0; j2 < names.length; j2++) {
//                    value.put(names[j2], tableName + names[j2] + j);
//                }
//                list1.add(value);
//            }
//        }
//
////        Map<String, String> data0 = new HashMap<String, String>();// 比较文件扩展名
////        for (String key : data.keySet()) {
////            data0.put("{{" + key + "}}", data.get(key));
////        }
////
////        if (subTableDatas != null) {
////            List<String> tableNames = new ArrayList<String>(subTableDatas.keySet());
////            for (String tabeName : tableNames) {
////                List<Map<String, String>> rows = subTableDatas.get(tabeName);
////                for (int i = 0; i < rows.size(); i++) {
////                    Map<String, String> row = rows.get(i);
////                    List<String> names1 = new ArrayList<String>(row.keySet());
////                    for (String cellName : names1) {
////                        String value = row.get(cellName);
////                        row.remove(cellName);
////                        row.put("{{" + cellName + "}}", value);
////                    }
////                }
////                subTableDatas.remove(tabeName);
////                subTableDatas.put("{{" + tabeName + "}}", rows);
////            }
////        }
//
//        addBookMarks(srcFile, toFile, data, subTableDatas);
////        toFile.deleteOnExit();
//        // System.out.println(subTables);
//    }

    public static void main2(String[] args) {
        String tableName0 = "{{table0}}";
        String table0 = tableName0.replaceFirst("[{]{2}", "\\\\{\\\\{").replaceFirst("[}]{2}", "\\\\}\\\\}");
        System.out.println(table0);
    }

    public static boolean addBookMarks(File srcFile, File toFile, Map<String, Map<String,Object>> data, Map<String,
            List<Map<String, Map<String,Object>>>> subTableDatas) {
        boolean success = false;
        Map<String, Map<String,Object>> data0 = new HashMap<String, Map<String,Object>>();// 比较文件扩展名
        for (String key : data.keySet()) {
            data0.put("{{" + key + "}}", data.get(key));
        }

        if (subTableDatas != null) {
            List<String> tableNames = new ArrayList<String>(subTableDatas.keySet());
            for (String tabeName : tableNames) {
                List<Map<String, Map<String,Object>>> rows = subTableDatas.get(tabeName);
                for (int i = 0; i < rows.size(); i++) {
                    Map<String, Map<String,Object>> row = rows.get(i);
                    List<String> names = new ArrayList<String>(row.keySet());
                    for (String cellName : names) {
                        Map<String,Object> value = row.get(cellName);
                        row.remove(cellName);
                        row.put("{{" + cellName + "}}", value);
                    }
                }
                subTableDatas.remove(tabeName);
                subTableDatas.put("{{" + tabeName + "}}", rows);
            }
        }


//        if (!success) {
//            System.out.println(data0);
//            printData(subTableDatas);
//            return success;
//        }

        FileOutputStream out = null;
        Closeable document = null;
        try {
            if (srcFile.getName().toLowerCase().endsWith("docx")) {
                success = addBookMark4Docx(srcFile, toFile, data0, subTableDatas);
            } else if (srcFile.getName().toLowerCase().endsWith("doc")) {
                HWPFDocument document1 = new HWPFDocument(new FileInputStream(srcFile));
                document = document1;
                Range range = document1.getRange();
                for (Map.Entry<String, Map<String,Object>> entry : data0.entrySet()) {
                    Map<String, Object> value = entry.getValue();
                    if(StrKit.str(value.get("type")).equals("String")){
                        range.replaceText(entry.getKey(), StrKit.str(entry.getValue().get("data")));
                    }else{
                        range.replaceText(entry.getKey(), "");
                    }
                }
                out = new FileOutputStream(toFile);
                document1.write(out);
                success = true;
                document1.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("套红错误", e);
        } finally {
            IOUtils.closeQuietly(out);
            IOUtils.closeQuietly(document);
        }
        return success;
    }

    public static boolean addBookMark4Docx(File srcFile, File toFile, Map<String, Map<String,Object>> data, Map<String, List<Map<String, Map<String,Object>>>> subTables) throws IOException {
        boolean success = false;
        OutputStream out = new FileOutputStream(toFile);
        XWPFDocument doc = new XWPFDocument(POIXMLDocument.openPackage(srcFile.getAbsolutePath()));
        try {
            List<XWPFParagraph> paragraphs = doc.getParagraphs();
            replaceParagraphs(data, paragraphs);
            if (subTables != null) {
                List<XWPFTable> tables = doc.getTables();
                replaceTables(data, subTables, tables);
            }
            doc.write(out);
            success = true;
        } catch (Exception e) {
            log.error("", e);
        } finally {
            IOUtils.closeQuietly(out);
            IOUtils.closeQuietly(doc);
        }
        return success;
    }

    // 表格套红
    // 这里简单取第一个表格 整个文件中第一个表格
    // 开始对表格操作
    // getrow(1) 为获取第二行数据
    private static long replaceTables(Map<String, Map<String,Object>> data, Map<String, List<Map<String, Map<String,Object>>>> subTables, List<XWPFTable> tables) throws IOException, InvalidFormatException {
        long count = 0;
        if (tables != null) {
            Set<String> tableNames = subTables.keySet();
            for (XWPFTable table : tables) {
                List<XWPFTableRow> rows = table.getRows();
                if (Strings.isNotEmpty(rows) && rows.size() > 1) {
                    int startRowIndex = rows.size() - 1;
                    XWPFTableRow templateRow = table.getRow(startRowIndex);// 最后一行模板行
                    List<XWPFTableCell> cells = templateRow.getTableCells();
                    if (Strings.isNotEmpty(cells)) {
                        XWPFTableCell firstCell = cells.get(0);
                        String text = firstCell.getText();
                        if (Strings.isNotBlank(text)) {
                            //获取表数据
                            List<String> collect = tableNames.stream().filter(t -> text.contains(t)).collect(Collectors.toList());
                            if(!collect.isEmpty()){
                                for (String tableName : collect) {
                                    String table0 = tableName.replaceFirst("[{]{2}", "\\\\{\\\\{").replaceFirst("[}]{2}", "\\\\}\\\\}");
                                    String firstValue = text.replaceAll(table0, "");
                                    HashMap<String, Object> firstValueMap = new HashMap<>();
                                    firstValueMap.put("type","String");
                                    firstValueMap.put("data",firstValue);
                                    List<XWPFParagraph> paragraphs = firstCell.getParagraphs();
                                    replaceParagraphs(text, firstValueMap, paragraphs);
                                    List<Map<String, Map<String,Object>>> rowDatas = subTables.get(tableName);
                                    if (Strings.isNotEmpty(rowDatas)) {
                                        for (int i = 0; i < rowDatas.size(); i++) {
                                            XWPFTableRow row = table.createRow();
                                            // 保证跟模板列一样
                                            if (row.getTableCells().size() < (cells.size() + 1)) {
                                                int len = cells.size() - row.getTableCells().size();
                                                for (int j = 0; j < len; j++) {
                                                    row.addNewTableCell();
                                                }
                                            }
                                        }
                                        replaeTable(rowDatas, table, startRowIndex); // 替换
                                    }
                                    table.removeRow(startRowIndex);// 删除模板行
                                }
                            }else{
                                if (table.getRows() != null) {
                                    for (XWPFTableRow row : table.getRows()) {
                                        for (XWPFTableCell cell : row.getTableCells()) {
                                            List<XWPFParagraph> paragraphs = cell.getParagraphs();
                                            replaceParagraphs(data, paragraphs);
                                        }
                                    }
                                }
                            }
//                            for (String tableName : tableNames) {
//                                if (text.indexOf(tableName) != -1) {// 取数据
//
//                                } else {
//
//                                }
//                            }
                        }
                    }
                }
            }
        }
        return count;
    }

    private static void replaeTable(List<Map<String, Map<String,Object>>> datas, XWPFTable table, int startRowIndex) throws IOException, InvalidFormatException {
        List<XWPFTableRow> rows = table.getRows();
        // 找到模板行的key
        Map<String, Map<String,Object>> keys = new LinkedHashMap<String, Map<String,Object>>();
        {
            XWPFTableRow row = rows.get(startRowIndex);// 模板行
            List<XWPFTableCell> cells = row.getTableCells();
            for (int i = 0; i < cells.size(); i++) {
                XWPFTableCell cell = cells.get(i);
                String text = cell.getText();
                if (Strings.isNotBlank(text)) {
                    text = text.trim();
                    if (text.startsWith("{") && text.endsWith("}")) {// 查找样式
                        List<XWPFParagraph> paragraphs0 = cell.getParagraphs();
                        if (Strings.isNotEmpty(paragraphs0)) {
                            List<XWPFRun> runs = paragraphs0.get(0).getRuns();
                            if (Strings.isNotEmpty(runs)) {
                                XWPFRun xwpfRun = runs.get(0);
                                //获取字体大小
                                int fontSize = xwpfRun.getFontSize();
                                //获取字体
                                String fontFamily = xwpfRun.getFontFamily() == null?"":xwpfRun.getFontFamily();
                                //获取字体颜色
                                String color = xwpfRun.getColor() == null?"":xwpfRun.getColor();
//                                DocStyle docStyle = new DocStyle(i, fontSize, fontFamily, color);
                                HashMap<String, Object> styleMap = new HashMap<>();
                                styleMap.put("index",i);
                                styleMap.put("fontSize",fontSize);
                                styleMap.put("fontFamily",fontFamily);
                                styleMap.put("color",color);
                                keys.put(text, styleMap);
//                                keys.put(text, new DocStyle(i, 14, xwpfRun.getFontFamily(), xwpfRun.getColor()));
                            }
                        }
                    }
                }
            }
        }

        int startIndex = startRowIndex + 1;// 数据行
        for (int i = 0; i < rows.size() - startIndex; i++) {
            XWPFTableRow row = rows.get(i + startIndex);// 模板行
            Map<String, Map<String,Object>> data = null;
            if (datas.size() > i) {
                data = datas.get(i);
            }

            if (data == null) {
                data = new HashMap<String, Map<String,Object>>();
            }

            List<XWPFTableCell> cells = row.getTableCells();
//            System.out.println("第" + i + "行，模板列名：" + keys + "\tdata:" + data);
            for (String key : keys.keySet()) {
                Map<String,Object> style = keys.get(key);
                Map<String,Object> value = data.get(key);
                XWPFTableCell cell = cells.get(Integer.parseInt(StrKit.str(style.get("index"))));
                List<XWPFParagraph> paragraphs = cell.getParagraphs();
                XWPFParagraph paragraph = null;
                if (Strings.isNotEmpty(paragraphs)) {
                    paragraph = paragraphs.get(0);
                }

                if (paragraph == null) {
                    paragraph = cell.addParagraph();
                }

                XWPFRun run2 = paragraph.createRun();
                if(value != null){
                    if(StrKit.str(value.get("type")).equals("String")){
                        String data1 = StrKit.str(value.get("data"));
                        run2.setFontFamily(StrKit.str(style.get("fontFamily")));
                        if(Integer.parseInt(StrKit.str(style.get("fontSize"))) != -1){
                            run2.setFontSize(Integer.parseInt(StrKit.str(style.get("fontSize"))));
                        }
                        run2.setColor(StrKit.str(style.get("color")));
                        run2.setText(data1, 0);
                    }else if(StrKit.str(value.get("type")).equals("inputStream")){
                        InputStream data1 = (InputStream)value.get("data");
                        int imgType = Integer.parseInt(StrKit.str(value.get("imgType")));
                        run2.addPicture(data1,imgType,"img",Units.toEMU(50),Units.toEMU(50));
//                        run2.setText("图片", 0);
                    }else{
                        run2.setText("", 0);
                    }
                }else{
                    run2.setText("", 0);
                }
            }
        }
    }

//    private static void setText(String key, String value, List<XWPFParagraph> paragraphs) {
//        for (XWPFParagraph paragraph : paragraphs) {
//            List<XWPFRun> runs = paragraph.getRuns();
//            if (Strings.isNotEmpty(runs)) {
//                XWPFRun titleFun = runs.get(0);
//                if (titleFun != null) {
//                    System.out.println(MessageFormat.format("key:{0},value:{1}", key, value));
//                    titleFun.setText(value);
//                }
//            }
//        }
//    }

    private static void replaceParagraphs(String key, Map<String,Object> value, List<XWPFParagraph> paragraphs) throws IOException, InvalidFormatException {
        for (XWPFParagraph paragraph : paragraphs) {
            List<XWPFRun> runs = paragraph.getRuns();
            // 获取文本段
            TextSegment tSegement = paragraph.searchText(key, new PositionInParagraph());
            if (tSegement != null) {
                int beginRun = tSegement.getBeginRun();
                int endRun = tSegement.getEndRun();
                // System.out.println(beginRun + " " + endRun);
                if (beginRun == endRun) {
                    // whole search string is in one Run
                    XWPFRun run = runs.get(beginRun);
                    String runText = run.getText(0);
                    if(StrKit.str(value.get("type")).equals("String")){
                        if(runText != null){
                            String replaced = runText.replace(key, StrKit.str(value.get("data")));
                            run.setText(replaced, 0);
                        }
                    }else if("inputStream".equals(StrKit.str(value.get("type")))){
                        InputStream data = (InputStream)value.get("data");
                        int imgType = Integer.parseInt(StrKit.str(value.get("imgType")));
                        run.addPicture(data,imgType,"img",Units.toEMU(200),Units.toEMU(200));
                    }else{
                        run.setText("", 0);
                    }

                } else {
                    // The search string spans over more than one Run
                    // Put the Strings together
                    StringBuilder b = new StringBuilder();
                    for (int runPos = beginRun; runPos <= endRun; runPos++) {
                        XWPFRun run = runs.get(runPos);
                        b.append(run.getText(0));
                    }
                    String connectedRuns = b.toString();

                    // The first Run receives the replaced String of all
                    // connected Runs
                    XWPFRun partOne = runs.get(beginRun);
                    if(StrKit.str(value.get("type")).equals("String")){
                        String replaced = connectedRuns.replace(key, StrKit.str(value.get("data")));
                        partOne.setText(replaced, 0);
                    }else if("inputStream".equals(StrKit.str(value.get("type")))){
                        InputStream data = (InputStream)value.get("data");
                        int imgType = Integer.parseInt(StrKit.str(value.get("imgType")));
                        partOne.addPicture(data,imgType,"img",Units.toEMU(200),Units.toEMU(200));
                    }else{
                        partOne.setText("", 0);
                    }
//                    String replaced = connectedRuns.replace(key, value);
//                    partOne.setText(replaced, 0);
                    // Removing the text in the other Runs.
                    for (int runPos = beginRun + 1; runPos <= endRun; runPos++) {
                        XWPFRun partNext = runs.get(runPos);
                        partNext.setText("", 0);
                    }
                }
            }
        }
    }

    private static void replaceParagraphs(Map<String, Map<String,Object>> data, List<XWPFParagraph> paragraphs) throws IOException, InvalidFormatException {
        for (Map.Entry<String, Map<String,Object>> replPair : data.entrySet()) {
            String oldText = replPair.getKey();
            Map<String,Object> newText = replPair.getValue();
            replaceParagraphs(oldText, newText, paragraphs);
        }
    }

    private static void printData(Map<String, List<Map<String, String>>> subTableDatas) {
        for (String tableName : subTableDatas.keySet()) {
            List<Map<String, String>> datas = subTableDatas.get(tableName);
            System.out.println(MessageFormat.format("table:{0}", tableName));
            for (Map<String, String> map : datas) {
                System.out.println(MessageFormat.format("row:{0}", map));
            }
        }
    }

    static class DocStyle {
        int index;
        int fontSize;
        String fontFamily;
        String color;

        DocStyle(int index, int fontSize, String fontFamily, String color) {
            this.index = index;
            this.fontSize = fontSize;
            this.fontFamily = fontFamily;
            this.color = color;
        }
    }
}
